package primetest.impl.dao;

import java.io.IOException;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import primetest.dto.TreatmentRecordDto;
import primetest.dto.TreatmentRecordDto.Medicine;
import primetest.impl.dao.DoctorDao;
import primetest.impl.dao.PatientDao;
import primetest.impl.dao.TreatmentRecordDao;
import primetest.impl.dao.Transaction;

public class TreatmentRecordDao implements Serializable {
	/**
	 *
	 */
	private static final long serialVersionUID = -889244211507360479L;

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private static List<TreatmentRecordDto> allItems = null;
	private static HashMap<Integer, TreatmentRecordDto> map = null;
	private static AtomicInteger count = null;
	private DoctorDao doctorDao;
	private PatientDao patientDao;
	private MedicineDao medicineDao;

	@Inject
	public TreatmentRecordDao(DoctorDao doctorDao, PatientDao patientDao, MedicineDao medicineDao) {
		this.doctorDao = doctorDao;
		this.patientDao = patientDao;
		this.medicineDao = medicineDao;
	}

	public List<TreatmentRecordDto> getTreatmentRecordList(
			Transaction transaction, int patientSeq, int doctorSeq,
			int departmentSeq, Date fromDate, Date endDate, int status)
			throws IOException {
		List<TreatmentRecordDto> re = new ArrayList<TreatmentRecordDto>();
		if (allItems == null) {
			getTreatmentRecordList(transaction);
		}

		for (TreatmentRecordDto t : allItems) {
			if ((t.getPatientSeq() == patientSeq || patientSeq == -1)
					&& (t.getDoctorSeq() == doctorSeq || doctorSeq == -1)
					&& (t.getDepartmentID() == departmentSeq || departmentSeq == -1)
					&& (t.getStatus() == status || status == -1)) {
				re.add(t);
			}
		}
		return re;
	}

	public List<TreatmentRecordDto> getTreatmentRecordList(
			Transaction transaction) throws IOException {
		if (allItems != null) {
			return allItems;
		}
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;
		map = new HashMap<Integer, TreatmentRecordDto>();
		int cnt = 0;
		try {

			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(GET_ALL);
			resultSet = prepareStatement.executeQuery();

			allItems = new ArrayList<TreatmentRecordDto>();

			while (resultSet.next()) {
				TreatmentRecordDto treatmentRecordDto = makeTreatmentRecordDto(
						transaction, resultSet);
				map.put(treatmentRecordDto.getSeq(), treatmentRecordDto);
				if (treatmentRecordDto.getSeq() > cnt) {
					cnt = treatmentRecordDto.getSeq();
				}
			}
			allItems = new ArrayList<TreatmentRecordDto>(map.values());
			count = new AtomicInteger(++cnt);
			return allItems;
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}
	}

	private TreatmentRecordDto makeTreatmentRecordDto(Transaction transaction,
			ResultSet resultSet) throws SQLException, IOException {
		TreatmentRecordDto treatmentRecordDto = new TreatmentRecordDto(
				resultSet.getInt(1), patientDao.getPatient(transaction,
						resultSet.getInt(2)), doctorDao.findDoctor(transaction,
						resultSet.getInt(3)), doctorDao.findDoctor(transaction,
								resultSet.getInt(4)), resultSet.getInt(5),
				resultSet.getString(6), resultSet.getFloat(7),
				resultSet.getString(8), resultSet.getString(9),
				resultSet.getDate(10), resultSet.getInt(11));
		List<Medicine> medicines = new ArrayList<Medicine>();
		for (String str : treatmentRecordDto.getMedcineIDsAndNums().split(":")) {
			if (!str.isEmpty()) {
				String[] strA = str.split("!");
				medicines.add(new Medicine(medicineDao.findMedicine(transaction, strA[0]), Integer.valueOf(strA[1])));
			}

		}
		treatmentRecordDto.setMedicines(medicines);
		return treatmentRecordDto;
	}

	public TreatmentRecordDto getTreatmentRecord(Transaction transaction,
			int treatmentRecordSeq) throws IOException {
		if (allItems == null) {
			getTreatmentRecordList(transaction);
		}
		return map.get(treatmentRecordSeq);
	}

	public void addTreatmentRecord(Transaction transaction,
			TreatmentRecordDto treatmentRecordDto) throws IOException {
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;
		if (map == null) {
			getTreatmentRecordList(transaction);
		}

		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(INSERT_ONE);
			treatmentRecordDto.setSeq(count.getAndIncrement());
			prepareStatement.setInt(1, treatmentRecordDto.getSeq());
			prepareStatement.setInt(2, treatmentRecordDto.getPatientSeq());
			prepareStatement.setInt(3, treatmentRecordDto.getDoctorSeq());
			prepareStatement.setInt(4, treatmentRecordDto.getGiveMedicineDoctorSeq());
			prepareStatement.setInt(5, treatmentRecordDto.getDepartmentID());
			prepareStatement.setString(6,
					treatmentRecordDto.getMedcineIDsAndNums());
			prepareStatement.setFloat(7, treatmentRecordDto.getFee());
			prepareStatement
					.setString(8, treatmentRecordDto.getDoctorComment());
			prepareStatement.setString(9, treatmentRecordDto.getSymptom());
			prepareStatement.setDate(10, treatmentRecordDto.getTreatDate());
			prepareStatement.setInt(11, treatmentRecordDto.getStatus());
			prepareStatement.executeUpdate();
			map.put(treatmentRecordDto.getSeq(), treatmentRecordDto);
			allItems.add(treatmentRecordDto);
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}
	}

	public void updateTreatmentRecord(Transaction transaction,
			TreatmentRecordDto treatmentRecordDto) throws IOException {
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;

		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(UPDATE_ONE);
			prepareStatement.setInt(11, treatmentRecordDto.getSeq());
			prepareStatement.setInt(1, treatmentRecordDto.getPatientSeq());
			prepareStatement.setInt(2, treatmentRecordDto.getDoctorSeq());
			prepareStatement.setInt(3, treatmentRecordDto.getGiveMedicineDoctorSeq());
			prepareStatement.setInt(4, treatmentRecordDto.getDepartmentID());
			prepareStatement.setString(5,
					treatmentRecordDto.getMedcineIDsAndNums());
			prepareStatement.setFloat(6, treatmentRecordDto.getFee());
			prepareStatement
					.setString(7, treatmentRecordDto.getDoctorComment());
			prepareStatement.setString(8, treatmentRecordDto.getSymptom());
			prepareStatement.setDate(9, treatmentRecordDto.getTreatDate());
			prepareStatement.setInt(10, treatmentRecordDto.getStatus());
			prepareStatement.executeUpdate();
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}

	}

	public void deleteTreatmentRecord(Transaction transaction,
			int treatmentRecordSeq) throws IOException {
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;

		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(DELETE_ONE);
			prepareStatement.setInt(1, treatmentRecordSeq);
			prepareStatement.executeUpdate();
			allItems.remove(map.remove(treatmentRecordSeq));
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}

	}

	private static final String GET_ALL = "select seq, patient_id, doctor_id, give_medicine_doctor_id, department_id,  MEDICNE_IDS_AND_NUMS, TOTAL_FEE, "
			+ "DOCTOR_COMMENT, SYMPTOM, TREAT_DATE, status from s_treatment_record order by seq";
	private static final String INSERT_ONE = "insert into s_treatment_record(seq, patient_id, doctor_id, give_medicine_doctor_id, department_id,  MEDICNE_IDS_AND_NUMS, TOTAL_FEE, "
			+ "DOCTOR_COMMENT, SYMPTOM, TREAT_DATE, status) values (?, ?, ?, ?, ?, ? , ? , ? , ? , ?, ?)";
	private static final String UPDATE_ONE = "update s_treatment_record set patient_id = ?,  doctor_id = ?, give_medicine_doctor_id= ?, department_id = ?,  MEDICNE_IDS_AND_NUMS = ?, TOTAL_FEE = ?, "
			+ "DOCTOR_COMMENT = ?, SYMPTOM = ?, TREAT_DATE = ?, status = ?  where seq = ?";
	private static final String DELETE_ONE = "delete from s_treatment_record where seq = ?";

}
